﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

//*******************************************************************
// Purpose:  Windows.Forms.Form dung de goi cac thu tuc va ham long running trong 1 thread
// Notes:    Người sử dụng sẽ trao vào AddressOf thủ tục, thủ tục có tham số hoặc function để chạy
//           Hỗ trợ thay đổi Description
//           - Properties:
//                ThreadFunction: AddressOf hàm 
//                ThreadSub: AddressOf thủ tục có tham số
//                Thread: AddressOf thủ tục không có tham số
// History:
//     [Programer]       [DD-MMM-YYYY]       [Action]
//     LuanNH            09-May-2007         Created
//*******************************************************************  

public class frmProgress : Form
{
    public frmProgress()
    {
        InitializeComponent();
        //
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        this.BackColor = Color.Transparent;
        //
        Activated += frmProgress_Activated;
    }
    #region "Contructor"

    private static frmProgress _instance;
    //// Note: Constructor is 'protected'
    //Protected Sub New()
    //End Sub
    //// Note: Dispose is 'protected'
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    //protected new void Dispose()
    //{
    //    _instance.Dispose();
    //    _instance = null;
    //    base.Dispose();
    //}
    //// Lock synchronization object
    private static object _syncLock = new object();
    // return the provider
    public static frmProgress Instance()
    {
        //// Support multithreaded applications through
        //// 'Double checked locking' pattern which (once
        //// the instance exists) avoids locking each
        //// time the method is invoked 
        if (_instance == null)
        {
            lock (_syncLock)
            {
                if (_instance == null)
                {
                    _instance = new frmProgress();
                    _instance.Tag = "MAIN_INIT";
                }
            }
        }
        return _instance;
    }
    #endregion

    private FunctionInvoker _ThreadFunction;
    private SubInvoker _ThreadSub;

    private MethodInvoker _ThreadMethod;
    public object ThreadInputObject;
    private object _ThreadOutputObject;
    //
    private System.Threading.Thread m_objThread;
    //
    private string m_sTextDescription;
    private string m_sTextFinish;
    //
    private Exception m_TheardException;
    private string m_sErrorRaise;
    //
    // Define the CS_DROPSHADOW constant

    private const int CS_DROPSHADOW = 131072;
    // Override the CreateParams property
    protected override System.Windows.Forms.CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ClassStyle = cp.ClassStyle | CS_DROPSHADOW;
            return cp;
        }
    }
    //

    public FunctionInvoker ThreadFunction
    {
        set
        {
            _ThreadFunction = value;
            _ThreadSub = null;
            _ThreadMethod = null;
            _ThreadOutputObject = null;
        }
    }

    public SubInvoker ThreadSub
    {
        set
        {
            _ThreadSub = value;
            _ThreadFunction = null;
            _ThreadMethod = null;
        }
    }

    public MethodInvoker Thread
    {
        set
        {
            _ThreadMethod = value;
            _ThreadSub = null;
            _ThreadFunction = null;
        }
    }

    public bool IsAbort
    {
        get
        {
            bool bStop = Globals.Object_GetValue<bool>(AppDomain.CurrentDomain.GetData("Progress_Abort"));
            return bStop;
        }
    }

    private bool _IsRunning;
    public bool IsRunning
    {
        get { return _IsRunning; }
    }

    //*******************************************************************
    // Purpose:  hàm Public để show progress
    // Notes:    Trong trường hợp hỗ trợ cancel thì phải có đoạn handle ThreadAbortException để xử lý
    //     - Inputs: 
    //               sDescription : init description text
    //               bAllowCancel : hỗ trợ cancel hay không
    //     - Return: Trả lại kết quả tính toán của ThreadFunction (nếu có)
    // History:
    //     [Programer]       [DD-MMM-YYYY]       [Action]
    //     LuânNH            09-May-2007         Created
    //     [Modifier]        [Modify Date]       Updated
    //*******************************************************************  
    internal object Show_Progress(string sStart, string sFinish)
    {
        m_sTextFinish = sFinish;
        return Show_Progress(sStart, false);
    }

    internal object Show_Progress()
    {
        m_sTextFinish = "";
        return Show_Progress("Loading ...", false);
    }

    internal object Show_Progress(string sStart)
    {
        m_sTextFinish = "";
        return Show_Progress(sStart, false);
    }

    internal object Show_Progress(string sStart, bool bAllowCancel)
    {
        //Prevent wrong call
        if (_ThreadMethod == null & _ThreadSub == null & _ThreadFunction == null)
        {
            throw new Exception("Nothing method or function assigned");
        }
        //Prevent wrong call
        if (this.Visible || (m_objThread != null))
        {
            if ((_ThreadFunction != null))
            {
                throw new Exception("Progress is running");
            }
            else
            {
                //Support call method in progress
                Dummy_Function();
                return null;
            }
        }
        _IsRunning = true;
        try
        {
            //m_sErrorRaise = "Init_Circle"
            Init_Circle(this.LoadingCircle);
            Init_Thread();
            //
            //m_sErrorRaise = "SetDescription"
            //
            if (string.IsNullOrEmpty(sStart))
            {
                sStart = "Loading ...";
            }
            else
            {
                if (!sStart.EndsWith("..."))
                {
                    sStart += " ...";
                }
            }
            m_sTextDescription = sStart;
            SetDescription();
            //
            cmdCancel.Visible = bAllowCancel;
            m_TheardException = null;
            //
            if (!bAllowCancel)
            {
                this.Width = 240;
            }
            //
            //m_sErrorRaise = "ShowDialog"
            //
            this.Tag = "MAIN_PROGRESS";
            this.TopMost = false;
            this.Timer_Event.Enabled = false;
            this.Owner = Form.ActiveForm;
            this.ShowInTaskbar = false;
            //
            //if (this.Owner != FormGlobals.GetActiveForm())
            //if(this.Owner!=Form.ActiveForm)
            //this.Owner = Form.ActiveForm;


            this.ShowDialog();
            //
            if (m_objThread.ThreadState == System.Threading.ThreadState.Running || m_objThread.ThreadState == System.Threading.ThreadState.WaitSleepJoin)
            {
                AppDomain.CurrentDomain.SetData("Progress_Stop", true);
                if (m_objThread.ThreadState == System.Threading.ThreadState.Running)
                {
                    while (m_objThread.ThreadState != System.Threading.ThreadState.Stopped)
                    {
                        System.Threading.Thread.Sleep(50);
                    }
                }
            }
            m_objThread.Abort();
            m_objThread = null;
            //
            this.Hide();
            //
            //if (this.Owner != null)
            //{
            //    this.Owner.Activate();
            //    this.Owner.TopMost = true;
            //    this.Owner.TopLevel = true;
            //}

            if ((m_TheardException != null))
            {
                throw m_TheardException;
            }
        }
        catch (Exception ex)
        {
            FormGlobals.Message_Error(ex);
            //throw ex;
            //throw Exception(m_sErrorRaise + ": " + ex.Message)
        }
        finally
        {
            m_TheardException = null;
            _IsRunning = false;
        }
        return _ThreadOutputObject;
    }

    private void Init_Thread()
    {
        if ((m_objThread != null))
            m_objThread.Abort();
        m_objThread = new System.Threading.Thread(Show_Circle);
        //m_objThread.IsBackground = True
    }

    private void Init_Circle(LoadingControl lc)
    {
        lc.StylePreset = LoadingControl.StylePresets.Custom;
        lc.OuterCircleRadius = 12;
        lc.InnerCircleRadius = 8;
        lc.NumberSpoke = 12;
        lc.SpokeThickness = 3;
        lc.RotationSpeed = 500 / lc.NumberSpoke;
        lc.Active = false;
    }
    //*******************************************************************
    // Purpose:  hàm Public để set description text
    // Notes:    
    //     - Inputs: 
    //               sDescription : description text
    // History:
    //     [Programer]       [DD-MMM-YYYY]       [Action]
    //     LuânNH            09-May-2007         Created
    //     [Modifier]        [Modify Date]       Updated
    //*******************************************************************  
    public void SetDescriptionText(string sDescription)
    {
        m_sTextDescription = sDescription;
        SetDescription();
    }

    private void SetDescription()
    {
        //If Me.InvokeRequired Then
        //    Me.Invoke(New MethodInvoker(AddressOf SetDescription))
        //Else
        //    'lbDescription.Text = m_sTextDescription
        //    'lbDescription.Refresh()
        //    'Me.Refresh()
        //End If
        lbDescription.Text = m_sTextDescription;
        AppDomain.CurrentDomain.SetData("Progress_Desc", m_sTextDescription);
    }
    //*******************************************************************
    // Purpose:  hàm Public để set Finish description text
    // Notes:    
    //     - Inputs: 
    //               sFinish : chuỗi Finish description text 
    // History:
    //     [Programer]       [DD-MMM-YYYY]       [Action]
    //     LuânNH            09-May-2007         Created
    //     [Modifier]        [Modify Date]       Updated
    //*******************************************************************  
    public void SetFinishText(string sFinish = "Data saved", int iDelay = 1000)
    {
        m_sTextDescription = sFinish;
        SetDescription();
        //Delay iDelay milisecond
        DateTime t = DateTime.Now;
        while ((DateTime.Now - t).TotalMilliseconds < iDelay)
        {
            System.Threading.Thread.Sleep(100);
            Application.DoEvents();
        }
    }

    public void SetVisible(bool bVisible)
    {
        AppDomain.CurrentDomain.SetData("Progress_Visible", bVisible);
        this.Visible = bVisible;
        if (bVisible)
        {
            Init_Thread();
            m_objThread.Start();
            Application.DoEvents();
            System.Threading.Thread.Sleep(200);
        }
        else
        {
            Application.OpenForms[0].Activate();
        }
    }

    //*******************************************************************
    // Purpose:  hàm để gọi trong Thread và Invoke thủ tục hoặc hàm
    // Notes:    
    // History:
    //     [Programer]       [DD-MMM-YYYY]       [Action]
    //     LuânNH            09-May-2007         Created
    //     [Modifier]        [Modify Date]       Updated
    //*******************************************************************  
    private void Dummy_Function()
    {
        try
        {
            if ((_ThreadMethod != null))
            {
                _ThreadMethod.Invoke();
            }
            else if ((_ThreadSub != null))
            {
                _ThreadSub.Invoke(ThreadInputObject);
            }
            else if ((_ThreadFunction != null))
            {
                _ThreadOutputObject = _ThreadFunction.Invoke(ThreadInputObject);
            }
        }
        catch (Exception ex)
        {
            m_TheardException = ex;
        }
        finally
        {
            _ThreadFunction = null;
            _ThreadSub = null;
            _ThreadMethod = null;
        }
    }

    private void cmdCancel_Click(System.Object sender, System.EventArgs e)
    {
        SetDescriptionText("Cancelling ...");
        AppDomain.CurrentDomain.SetData("Progress_Abort", true);
        cmdCancel.Enabled = false;
    }

    private void Timer_Event_Tick(object sender, System.EventArgs e)
    {
        try
        {
            if (Globals.Object_GetValue<string>(this.Tag) == "CHILD")
            {
                lbDescription.Text = Globals.Object_GetValue<string>(AppDomain.CurrentDomain.GetData("Progress_Desc"));
                bool bStop = Globals.Object_GetValue<bool>(AppDomain.CurrentDomain.GetData("Progress_Stop"));
                if (bStop)
                {
                    this.Hide();
                }
                else
                {
                    bStop = !Globals.Object_GetValue<bool>(AppDomain.CurrentDomain.GetData("Progress_Visible"));
                    if (bStop)
                        this.Hide();
                }
                if (bStop)
                    Timer_Event.Enabled = false;
            }
            else if (Globals.Object_GetValue<string>(this.Tag) == "MAIN_PROGRESS")
            {
                bool bStop = Globals.Object_GetValue<bool>(AppDomain.CurrentDomain.GetData("Progress_Abort"));
            }

        }
        catch
        {
        }
    }

    private void Show_Circle()
    {
        frmProgress f = new frmProgress();
        try
        {
            m_sErrorRaise = "Init Child";
            Init_Circle(f.LoadingCircle);
            f.LoadingCircle.Active = true;
            f.Timer_Event.Interval = 75;
            f.Timer_Event.Enabled = true;
            f.lbDescription.Text = m_sTextDescription;
            f.Tag = "CHILD";
            f.Width = this.Width;
            f.TopMost = this.TopMost;
            f.cmdCancel.Visible = this.cmdCancel.Visible;
            f.cmdCancel.TabStop = false;
            m_sErrorRaise = "Show Child";
            f.ShowInTaskbar = false;
            f.StartPosition = FormStartPosition.Manual;
            f.Location = this.Location;
            //f.TopMost = true;
            f.ShowDialog();
        }
        catch
        {
            
        }
        finally
        {
            f.Timer_Event.Enabled = false;
            f.LoadingCircle.Active = false;
            f.Close();
        }
    }

    private void frmProgress_Activated(object sender, System.EventArgs e)
    {
        try
        {
            if (Globals.Object_GetValue<string>(this.Tag) == "MAIN_PROGRESS")
            {
                if (m_objThread == null)
                {
                    //Throw New Exception("Thread is nothing")
                    this.Close();
                    return;
                }
                if (m_objThread.ThreadState == System.Threading.ThreadState.Running || m_objThread.ThreadState == System.Threading.ThreadState.Stopped)
                    return;
                //
                AppDomain.CurrentDomain.SetData("Progress_Abort", false);
                AppDomain.CurrentDomain.SetData("Progress_Stop", false);
                AppDomain.CurrentDomain.SetData("Progress_Visible", true);
                //
                m_sErrorRaise = "Thread start";
                //
                m_objThread.Start();
                //
                Application.DoEvents();
                System.Threading.Thread.Sleep(100);
                //
                m_sErrorRaise = "Process Function";
                //
                Dummy_Function();
                //
                if (!string.IsNullOrEmpty(m_sTextFinish))
                {
                    SetFinishText(m_sTextFinish);
                    m_sTextFinish = "";
                }
                //
                this.Close();
            }
            else
            {
                Timer_Event.Enabled = true;
            }
        }
        catch (Exception ex)
        {
          
            m_TheardException = ex;
        }
    }
    //public frmProgress()
    //{

    //}

    internal Timer Timer_Event;
    private IContainer components;
    internal Button cmdCancel;
    public Label lbDescription;

    private void InitializeComponent()
    {
            this.components = new System.ComponentModel.Container();
            this.Timer_Event = new System.Windows.Forms.Timer(this.components);
            this.cmdCancel = new System.Windows.Forms.Button();
            this.lbDescription = new System.Windows.Forms.Label();
            this.Panel1 = new System.Windows.Forms.Panel();
            this.LoadingCircle = new LoadingControl();
            this.Panel1.SuspendLayout();
            this.SuspendLayout();
            // 
            // Timer_Event
            // 
            this.Timer_Event.Interval = 50;
            this.Timer_Event.Tick += new System.EventHandler(this.Timer_Event_Tick);
            // 
            // cmdCancel
            // 
            this.cmdCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
            this.cmdCancel.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            this.cmdCancel.Location = new System.Drawing.Point(211, 5);
            this.cmdCancel.Name = "cmdCancel";
            this.cmdCancel.Size = new System.Drawing.Size(75, 23);
            this.cmdCancel.TabIndex = 2;
            this.cmdCancel.Text = "Cancel";
            this.cmdCancel.UseVisualStyleBackColor = true;
            this.cmdCancel.Visible = false;
            this.cmdCancel.Click += new System.EventHandler(this.cmdCancel_Click);
            // 
            // lbDescription
            // 
            this.lbDescription.AutoSize = true;
            this.lbDescription.Location = new System.Drawing.Point(38, 10);
            this.lbDescription.Name = "lbDescription";
            this.lbDescription.Size = new System.Drawing.Size(59, 13);
            this.lbDescription.TabIndex = 1;
            this.lbDescription.Text = "Loading ...";
            // 
            // Panel1
            // 
            this.Panel1.BackColor = System.Drawing.Color.Transparent;
            this.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.Panel1.Controls.Add(this.LoadingCircle);
            this.Panel1.Controls.Add(this.cmdCancel);
            this.Panel1.Controls.Add(this.lbDescription);
            this.Panel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.Panel1.Location = new System.Drawing.Point(0, 0);
            this.Panel1.Name = "Panel1";
            this.Panel1.Size = new System.Drawing.Size(292, 36);
            this.Panel1.TabIndex = 1;
            // 
            // LoadingCircle
            // 
            this.LoadingCircle.Active = false;
            this.LoadingCircle.Color = System.Drawing.Color.SteelBlue;
            this.LoadingCircle.Location = new System.Drawing.Point(6, 4);
            this.LoadingCircle.Name = "LoadingCircle";
            this.LoadingCircle.RotationSpeed = 100;
            this.LoadingCircle.Size = new System.Drawing.Size(28, 26);
            this.LoadingCircle.TabIndex = 3;
            this.LoadingCircle.Text = "loadingControl1";
            // 
            // frmProgress
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 36);
            this.ControlBox = false;
            this.Controls.Add(this.Panel1);
            this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Name = "frmProgress";
            this.ShowIcon = false;
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.TopMost = true;
            this.Activated += new System.EventHandler(this.frmProgress_Activated);
            this.Panel1.ResumeLayout(false);
            this.Panel1.PerformLayout();
            this.ResumeLayout(false);

    }

    internal Panel Panel1;
    private LoadingControl LoadingCircle;
}

